#pragma once
#include <iostream>
#include <vector>
#include <time.h>
//定长内存池
// template <typename T>
//class ObjectPool
//{
//
//};

#ifdef _WIN32
#include <windows.h>
#else
#endif

inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
	void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
	//linux下的brk和mmp
#endif
	if (ptr == nullptr)
		throw std::bad_alloc();
	
	return ptr;
}

template <class T>
class ObjectPool
{
public:
	T* New()
	{
		T* obj = nullptr;
		if (_freeList)
		{
			void* next = (*(void**)_freeList);
			obj = (T*)_freeList;
			_freeList = next;
		}
		else
		{
			//剩余空间不够开出一个对象的大小时，则重新开出大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 128 * 1024;
				//_memory = (char*)malloc(_remainBytes);
				_memory = (char*)SystemAlloc(_remainBytes >> 13);
				if (_memory == nullptr)
				{
					throw std::bad_alloc();
				}
			}

			obj = (T*)_memory;
			size_t ObjSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			_memory += ObjSize; //意思是_memory指针向后移动ObjSize,以便用于存储自由链表指针
			_remainBytes -= ObjSize;//减去自由链表指针存储的大小
			return obj;
		}

		//定位new方法
		new(obj)T;
		//正常情况下，new会在堆上上申请空间，然后再调用构造函数，
		//但是使用定位new方法，无需在堆上申请空间，会在显示的内存空间直接调用构造
		//函数，进行初始化
        // 定位 new 的行为：
        // 不分配内存，而是在已有的内存空间上直接调用构造函数
        // 语法格式：new (内存地址) 类型(构造参数)

		return obj;
	}

	void Delete(T* obj)
	{
		obj->~T();
		//显示自动调用析构函数，自动清理对象，例如string的对象

		//头插
		*((void**)obj) = _freeList;//
		_freeList = obj;
	}
private:
	char* _memory = nullptr;		//定长内存空间，指向大块内存空间
	void* _freeList = nullptr;		//返回来自由链表的头指针
	size_t _remainBytes = 0;	    //剩余大块内存空间字节数
};

